package com.jbh.recordlibrary.m;

import android.content.Context;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.Toast;

import com.jbh.recordlibrary.f.Pcm2Wav;
import com.jbh.recordlibrary.i.AddAudioRecordListener;
import com.jbh.recordlibrary.u.LogUtil;
import com.jbh.recordlibrary.u.SdcardUtil;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;


public class AudioRecordManager {

    public final static String TAG = "Recording";

    /**
     *
     */
    private static AudioRecordManager manager;

    /**
     * 回调
     */
    private AddAudioRecordListener addAudioRecordListener;

    /**
     * @param addAudioRecordListener
     */
    public void addAudioRecordListener(AddAudioRecordListener addAudioRecordListener) {
        this.addAudioRecordListener =addAudioRecordListener;
    }

    /**
     * 设置音频采样率，44100是目前的标准，但是某些设备仍然支持22050，16000，11025
     */
    private static final int sampleRateInHz = 16000;
    /**
     * 单声道
     * AudioFormat.CHANNEL_IN_MONO
     * 双声道
     * AudioFormat.CHANNEL_IN_STEREO
     */
    private static final int channelConfig = AudioFormat.CHANNEL_IN_MONO;
    /**
     * 音频数据格式：每个样本16位
     */
    private static final int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
    /**
     * 音频获取源 麦克风
     */
    public final static int audioSource = MediaRecorder.AudioSource.MIC;

    /**
     * 计算缓冲录音数据的字节数组的大小。AudioRecord 需要一个容器来缓冲来自硬件的音频信息。
     */
    private int recBufSize;
    /**
     * 创建AudioRecord对象
     */
    private AudioRecord audioRecord;
    /**
     * 正在录音
     */
    public boolean isRecording = false;
    /**
     * 录音暂停
     */
    public boolean isPause = false;
    /**
     * 正在写入文件
     */
    public boolean isWriting = false ;

    /**
     * 缓冲区数据
     */
    private ArrayList<Short> inBuf = new ArrayList<>();
    private ArrayList<Short> totalInBuf = new ArrayList<>() ;

    /**
     * 录音数据写入文件数据
     */
    private ArrayList<byte[]> write_data = new ArrayList<>();
    /**
     * 为了节约绘画时间，每0.2个像素画一个数据
     */
    private float divider = 6f;
    /**
     * 计算在当前view上能绘制音频线条数
     *
     */
    private int recordNum ;
    /**
     * 波形图绘制距离右边的距离
     */
    private int marginRight=30;
    /**
     * 需要绘制view的宽度Width
     */
    private int width=1080;
    /**
     * 保存pcm文件路径
     */
    private String savePcmPath ;
    /**
     * 保存wav文件路径
     */
    private String saveWavPath;


    public long lastTime ;
    /**每取一帧间隔时间  单位毫秒*/
    public int speedTime = 1; //


    /**
     * 构成方法
     * <p>
     * 实力化 录音对象
     */
    private AudioRecordManager() {
        recBufSize = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat);
    }



    public static AudioRecordManager getInstance() {
        if (null == manager) {
            synchronized (AudioRecordManager.class) {
                if (null == manager) {
                    manager = new AudioRecordManager();
                }
            }
        }
        return manager;
    }



    private Handler handler = new Handler();
    /**录音时间*/
    private long recordTime ;

    private int temp = 50;

    private Runnable runnable = new Runnable() {
        @Override
        public void run() {
            handler.postDelayed(this, temp);
            if (isRecording && !isPause){
                recordTime += temp ;
            }
            if (addAudioRecordListener != null) {
                addAudioRecordListener.recordCurrentTime(recordTime);
            }
        }
    };


    /**
     * 启动定时器
     */
    private void startTime(){
        handler.postDelayed(runnable, temp);
    }


    /**
     * 停止定时器
     */
    private void stopTime(){
        handler.removeCallbacks(runnable);
    }


    /**
     * 计算在当前view上能绘制音频线条数
     *
     */
    private void initDrawNum(){
        recordNum = (int) (width / divider);
        Log.v("[recordNum] ->"," recordNum = "+recordNum);
    }



    /**
     *
     * 距离右边的距离
     *
     * @param marginRight
     */
    public void setMarginRight(int marginRight) {
        this.marginRight = marginRight;
    }



    /**
     * 设置间隔绘制音频
     *
     * @param divider
     */
    public AudioRecordManager setDivider(float divider) {
        this.divider = divider;
        return this;
    }




    /**
     * 开始录音
     *
     */
    public void start(Context context){
        if (context == null) return;
        audioRecord = new AudioRecord(audioSource, sampleRateInHz, channelConfig, audioFormat, recBufSize);
        if (addAudioRecordListener!=null){
            addAudioRecordListener.start();
            if (addAudioRecordListener.getDrawWaveWidth()>0){
                width = addAudioRecordListener.getDrawWaveWidth();
            }
            initDrawNum() ;
        }

        long time = System.currentTimeMillis();
        savePcmPath = SdcardUtil.getSaveDir(context)+ File.separator + "record_pcm_"+time+".pcm";
        saveWavPath = SdcardUtil.getSaveDir(context)+ File.separator + "record_wav_"+time+".wav";

        Log.v(TAG,"[savePcmPath]="+savePcmPath);
        Log.v(TAG,"[saveWavPath]="+saveWavPath);
        Log.v(TAG,"[start]");
        isRecording = true ;
        isWriting = true ;
        recordTime = 0 ;

        /**录音计时器*/
        startTime();
        /**将录音文件写入文件*/
        new Thread(new WriteRecordFileToSdcard()).start();
        /**开始录音*/
        new RecordTask(audioRecord,recBufSize).execute();
    }



    /**
     * 暂停之后继续开始
     */
    public void reStart(){
        if (addAudioRecordListener!=null){
            addAudioRecordListener.reStart();
        }
        isRecording = true ;
        isPause = false ;
        isWriting  = true;
        Log.v(TAG,"[reStart]");
    }



    /**
     * 暂停录音
     */
    public void pause(){
        this.isPause=true ;
        /**
         * 暂停的时候  转WAV
         *
         * 将pcm格式转换成wav 其实就尼玛加了一个44字节的头信息
         */
        Pcm2Wav p2w = new Pcm2Wav();
        try {
            p2w.convertAudioFiles(savePcmPath, saveWavPath);
            if (addAudioRecordListener!=null){
                addAudioRecordListener.pause();
                addAudioRecordListener.totalRecord(divider,oneSecondLength(),totalInBuf,totalTime(),totalLength(),saveWavPath);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }







    /**
     * 停止录音
     */
    public void stop(){
        isRecording = false ;
        isWriting = false ;
        isPause = false ;
        totalInBuf.clear();
        inBuf.clear();
        stopTime();

        if (audioRecord!=null){
            audioRecord.stop();
            audioRecord = null ;
        }

    }





    /**
     * 绘制的总长度
     *
     * @return
     */
    private float totalLength() {
        return divider * totalInBuf.size();
    }



    /**
     * 绘制的总时间
     *
     * @return
     */
    private long totalTime() {
        return recordTime;
    }



    /**
     * 一秒需要绘制的长度
     * @return
     */
    private float oneSecondLength(){
        float f = (float) (totalLength() *1.0 / totalTime());
        return f * 1000;
    }





    /**
     * 异步录音程序
     *
     * @author cokus
     */

    private class RecordTask extends AsyncTask<Object, Object, Object> {
        private int recBufSize;
        private AudioRecord audioRecord;
        Object mLock;
        public RecordTask(AudioRecord audioRecord, int recBufSize) {
            this.audioRecord = audioRecord;
            this.recBufSize = recBufSize;
            mLock = new Object();
            totalInBuf.clear();
            inBuf.clear();
        }

        @Override
        protected Object doInBackground(Object... params) {
            try {
                short[] buffer = new short[recBufSize];
                /**开始录制*/
                audioRecord.startRecording();
                while (isRecording) {

                    if (!isPause){

                        /**
                         * 从MIC保存数据到缓冲区
                         */
                        int readSize = audioRecord.read(buffer, 0, recBufSize);

                        synchronized (inBuf) {
                            float v = 0 ;
                            if(System.currentTimeMillis() - lastTime >= speedTime){
                                for (int i = 0; i < readSize; i++) {
                                     v = buffer[i] * buffer[i];
                                }
                                double val = recordFB(readSize,v);
                                /*把缓冲区数据存起来*/
                                inBuf.add((short) val);
                                /*把缓冲区数据存起来*/
                                totalInBuf.add((short) val);
                                lastTime = System.currentTimeMillis();
                            }
                        }

                        publishProgress();

                        /**
                         * 更新主线程中的UI
                         */
                        if (AudioRecord.ERROR_INVALID_OPERATION != readSize) {
                            synchronized (write_data) {
                                byte bys[] = new byte[readSize * 2];
                                /**
                                 * 因为arm字节序问题，所以需要高低位交换
                                 */
                                for (int i = 0; i < readSize; i++) {
                                    byte ss[] = getBytes(buffer[i]);
                                    bys[i * 2] = ss[0];
                                    bys[i * 2 + 1] = ss[1];
                                }
                                write_data.add(bys);
                            }
                        }
                    }
                }

                Log.v(TAG,"[isWriting]"+isWriting);

                isWriting = false;
            } catch (Throwable t) {
                Message msg = new Message();
                msg.arg1 = -2;
                msg.obj = t.getMessage();
            }
            return null;
        }




        @Override
        protected void onProgressUpdate(Object... values) {
            ArrayList<Short> buf ;
            synchronized (inBuf) {
                if (inBuf.size() == 0) return;
                /**
                 * 每次计算绘制满数量需要重置
                 */
                while (inBuf.size() > recordNum) {
                    inBuf.remove(0);
                }
                /**
                 * 保存
                 */
                buf = (ArrayList<Short>) inBuf.clone();
                /**
                 * 把缓冲区数据画出来
                 */
                if (addAudioRecordListener != null) {
                    addAudioRecordListener.recordBuffer(divider, buf);
                }
            }
            super.onProgressUpdate(values);
        }
    }




    /**
     * @param readSize   读取录音数据长度
     * @return
     *
     */
    public double recordFB(int readSize , double val){
        // 平方和除以数据总长度，得到音量大小。
        double mean = val / (double) readSize;
        double volume = 10 * Math.log10(mean);
        LogUtil.LOG_V("[recordFB]->volume = "+volume);
        return volume ;
    }



    /**
     * 高低位交换
     *
     * @param s
     * @return
     */
    public byte[] getBytes(short s) {
        byte[] buf = new byte[2];
        for (int i = 0; i < buf.length; i++) {
            buf[i] = (byte) (s & 0x00ff);
            s >>= 8;
        }
        return buf;
    }




    /**
     * 将录音的文字写入文件当中去
     */
    public class WriteRecordFileToSdcard implements Runnable {

        @Override
        public void run() {
            try {
                FileOutputStream fosPcm = null;
                File filePcm = null;
                try {
                    filePcm = new File(savePcmPath);
                    filePcm.createNewFile();
                    // 建立一个可存取字节的文件
                    fosPcm = new FileOutputStream(filePcm);

                    File fileWav= new File(saveWavPath);
                    fileWav.createNewFile();
                } catch (Exception e) {
                    e.printStackTrace();
                }

                while (isWriting || write_data.size() > 0) {
                    byte[] buffer = null;
                    synchronized (write_data) {
                        if(write_data.size() > 0){
                            buffer = write_data.get(0);
                            write_data.remove(0);
                        }
                    }
                    try {
                        if(buffer != null){
                            fosPcm.write(buffer);
                            fosPcm.flush();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }

                fosPcm.close();

                /**
                 * 将pcm格式转换成wav 其实就尼玛加了一个44字节的头信息
                 */
                Pcm2Wav p2w = new Pcm2Wav();
                p2w.convertAudioFiles(savePcmPath, saveWavPath);

                if (addAudioRecordListener!=null){
                    addAudioRecordListener.stop(saveWavPath);
                    addAudioRecordListener.totalRecord(divider,oneSecondLength(),totalInBuf,totalTime(),totalLength(),saveWavPath);
                }

            } catch (Throwable e) {
                e.printStackTrace();
            }
        }
    }
}
